<?php


namespace app\common;


class Captcha extends Base
{
    protected $config = [
        //验证码过期时间
        'expire'    =>  1800,
        //验证码加密密钥
        'keys'      =>  'shisai.hungry',
        //字体大小
        'fontSize'  =>  5,
        //验证码长度
        'fontLength'    =>  4,
        //画布宽度
        'imgWidth'  =>  100,
        //画布高度
        'imgHeight' =>  30,
        //验证码
        'code'      =>  ''
    ];
    private $im = null;     //验证码图片实例
    private $color = null;  //验证码字体颜色

    /**
     * 验证码判断
     * @param $code
     * @return bool
     */
    public function check(string $code){
        $keys = $this->authcode($this->config['keys']);
        $code = strtoupper($code);
        $key = md5($code.$keys);
        $secode = app('mycache')->get($key);
        if (empty($code) || empty($secode)){
            return false;
        }
        if (time() - $secode['expire_time'] > $this->config['expire']){
            app('mycache')->del($key);
            return false;
        }
        if ($code != $secode['code']){
            return false;
        }
        app('mycache')->del($key);
        return true;
    }

    /**
     * 创建验证码将验证码保存到缓存当中
     * @return \think\Response
     */
    public function entry(){
        //创建画布
        $this->im = imagecreate($this->config['imgWidth'],$this->config['imgHeight']);
        //创建字体颜色
        $this->color = imagecolorallocate($this->im,mt_rand(200,255),mt_rand(200,255),mt_rand(200,255));
        //创建背景
        imagefilledrectangle($this->im,0,0,$this->config['imgWidth'],$this->config['imgHeight'],$this->color);
        //创建干扰线
        $this->createLine();
        //创建干扰点
        $this->createSpot();

        //创建验证码
        //产生随机字符串的数组
        $arr_code = array_merge(range('a','z'),range(0,9),range('A','Z'));
        //打乱数组
        shuffle($arr_code);
        //随机获取下标
        $arr_index = array_rand($arr_code,$this->config['fontLength']);

        //将验证码循环出来
        foreach ($arr_index as $index){
            $this->config['code'] .= $arr_code[$index];
        }
        //将验证码写入到图像
        for ($i=0;$i<strlen($this->config['code']);$i++){
            $color = imagecolorallocate($this->im,mt_rand(0,100),mt_rand(0,100),mt_rand(0,100));
            $x = ($i*$this->config['imgWidth']/$this->config['fontLength'])+mt_rand(0,10);
            imagestring($this->im,5,$x,mt_rand(0,15),$this->config['code'][$i],$color);
        }

        $key         = $this->authcode($this->config['keys']);
        $code        = strtoupper($this->config['code']);
        $secode      = [
            'code'          =>  $code,
            'expire_time'   =>  time()
        ];
        app('mycache')->set(md5($code.$key),$secode,300);

        ob_start();
        // 输出图像
        imagepng($this->im);
        $content = ob_get_clean();
        imagedestroy($this->im);
        return response($content, 200, ['Content-Length' => strlen($content)])->contentType('image/png');
    }

    /**
     * 创建干扰线
     */
    private function createLine(){
        //循环获取干扰线
        for ($i=0;$i<$this->config['fontLength']+5;$i++){
            $lineColor = imagecolorallocate($this->im,mt_rand(100,255),mt_rand(100,255),mt_rand(100,255));
            imageline($this->im,mt_rand(0,$this->config['imgWidth']),mt_rand(0,$this->config['imgHeight']),mt_rand(0,$this->config['imgWidth']),mt_rand(0,$this->config['imgHeight']),$lineColor);
        }
    }

    /**
     * 创建干扰点
     */
    private function createSpot(){
        $spot = mt_rand(1,200);
        for ($i=1;$i<$spot;$i++){
            $color = imagecolorallocate($this->im,mt_rand(100,255),mt_rand(100,255),mt_rand(100,255));
            $x = mt_rand(0,$this->config['imgWidth']);
            imagestring($this->im,1,$x,mt_rand(0,$this->config['imgHeight']),'.',$color);
        }
    }

    /**
     * 加密验证码
     * @param $str
     * @return string
     */
    private function authcode($str)
    {
        $key = substr(md5($this->config['keys']), 5, 8);
        $str = substr(md5($str), 8, 10);
        return md5($key . $str);
    }
}